#include <stdio.h>
#include <stdlib.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

/*This Random Test Will Test the Great Hall Card. The Great Hall card has a player draw a
 * card and increments the number of actions by one. */

#define NOISY_TEST 0		//debug mode
#define NUM_TESTS 10000	
#define SEED 1003		//needed to run dominion.c
#define MAX_CARD treasure_map 	//max integer representation of card in dominion.c

typedef struct gameState gameState;

//helper function to initialize game struct to 0's
void clearGameState(struct gameState *G) {
	int i;
	for (i=0; i<sizeof(struct gameState); i++) {
		((char *)G)[i] = 0;
	}
}

int main (int argc, char *argv[]) {

	int i, j, k;
	int currentPlayer, handCount, deckCount, discardCount;	//relevant to refactored adventurer card in dominion.c
	int cur_card = 0;
	int passed_tests = 0;
	int failed_test = 0;
	int gh_not_discarded = 0;
	int handCount_test, numactions_test, discard_test, played_test = 0;	
	
	//create two gameStates. Our random test works by testing our function on two equivalent gameStates and comparing them
	struct gameState G1, G2;
	
	//initialize random number using rngs.h library
	SelectStream(1);
	PutSeed((long)SEED);
	
	//main test loop
	for (i=0; i < NUM_TESTS; i++) {
	  
	  if (NOISY_TEST) { printf("****************************\nTest number: %d\n", i+1); }
	  failed_test = 0;
	  gh_not_discarded = 0;
	  
	  //blank each game state
	  clearGameState(&G1);
	  clearGameState(&G2);
	  
	  //get a random # of valid players (1-4), and make it their turn.
	  currentPlayer = (int)(Random()*4);
	  G1.numActions = G2.numActions = (int)(Random()*3);		//game only allow up to two here, so randomly get 0, 1 or 2.
	  G1.whoseTurn = currentPlayer;
	  G2.whoseTurn = currentPlayer;
	  if (NOISY_TEST) { printf("currentPlayer is: %d\n", currentPlayer); }
	  
	  //get a random handCount, discardCount and deckCount, making sure we have at least two in the hand.
	  handCount = (int)(Random()*25) + 2;
	  if (NOISY_TEST) { printf("handCount is %d\n", handCount); }
	  discardCount = (int)(Random()*25) + 2;
	  if (NOISY_TEST) { printf("discardCount is %d\n", discardCount); }
	  deckCount = (int)(Random()*25)+2;
	  if (NOISY_TEST) { printf("deckCount is %d\n", deckCount); }
	  
	  //Create a random hand, deck, and discard pile for our player.
	  //Hand
	  for (j=0; j < handCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     G1.hand[currentPlayer][j] = G2.hand[currentPlayer][j] = cur_card;		//place card in handCount
	  }
	  
	  //Deck
	  for (j=0; j < deckCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     G1.deck[currentPlayer][j] = G2.deck[currentPlayer][j] = cur_card;		//place card in deck
	  }
	  
	  //Discard
	  for (j=0; j < discardCount; j++) {
	     cur_card = (int)(Random()*MAX_CARD);					//random card
	     G1.discard[currentPlayer][j] = G2.discard[currentPlayer][j] = cur_card;	//place card in discard
	  }
	  
	  //add great_hall card to player's hand. update gameState with our randomly assigned hand, deck, and discard counts.
	  G1.handCount[currentPlayer] = G2.handCount[currentPlayer] = handCount;
	  G1.handCount[currentPlayer]++;
	  G2.handCount[currentPlayer]++;
	  
	  G1.hand[currentPlayer][handCount] = G2.hand[currentPlayer][handCount] = great_hall;
	  G1.deckCount[currentPlayer] = G2.deckCount[currentPlayer] = deckCount;
	  G1.discardCount[currentPlayer] = G2.discardCount[currentPlayer] = discardCount;
	  
	  if (NOISY_TEST) {
	    for (k=0; k < G1.handCount[currentPlayer]; k++) {
	      cur_card = G1.hand[currentPlayer][k];
	      printf("Before Card Effect -- Player %d: Card %d is %d\n", currentPlayer, k, cur_card);
	    }
	  }
	  
	  //Call the cardEffect on only the first gameState.
	  cardEffect(great_hall, 0, 0, 0, &G1, handCount, 0);
	  
	  if (NOISY_TEST) {
	    printf("******************************\n");
	    for (k=0; k < G1.handCount[currentPlayer]; k++) {
	      cur_card = G1.hand[currentPlayer][k];
	      printf("After Card Effect -- Player %d: Card %d is %d\n", currentPlayer, k, cur_card);
	    }
	  }
	  
	  //test that the handCount for currentPlayer is the same (added one card, discarded great_hall)
	  if (G1.handCount[currentPlayer] != G2.handCount[currentPlayer]) {
	    printf("Test for handCount being the same FAILED: Expected %d cards in hand, have %d\n", G2.handCount[currentPlayer], G1.handCount[currentPlayer]);
	    failed_test = 1;
	  } else {
	    handCount_test++;
	  }
	  
	  //test that num_Actions was incremented by one. Do this by comparing the gameStates.
	  if (G1.numActions != G2.numActions + 1) {
	      printf("Test for numActions incrementing by one FAILED: Expected %d actions, hand has %d actions.\n", G2.numActions, G1.numActions);
	      failed_test = 1;
	  } else {
	      numactions_test++;
	  }
	  
	  //test great_hall card has been discarded from hand
	    if (G1.hand[currentPlayer][G1.handCount[currentPlayer]] == great_hall) {
	      printf("Test for discarding great_hall FAILED: The card is still at the top of the hand.\n");
	      failed_test = 1;
	      gh_not_discarded = 1;
	    }
	    if (gh_not_discarded == 0) {
	      discard_test++;
	    }
	  
	  //test great_hall card is in played card pile. testing this way works because it was a blank game state.
	  if (G1.playedCards[G1.playedCardCount - 1] != great_hall) {
	    printf("Test for great_hall in playedCards FAILED: At the top of the playedCard pile is %d\n", G1.playedCards[G1.playedCardCount]);
	    failed_test = 1;
	  } else {
	    played_test++;
	  }
	  
	  //increment a passed_test iteration if all tests succeeded.
	  if (failed_test == 0) {
	    passed_tests++;
	  }
	  
	}
	
	//print the overall result of the tests
	printf("\n************OVERALL TEST RESULTS***********\nOut of %d tests, %d tests completed without any failures\n", NUM_TESTS, passed_tests);
	printf("Out of %d tests, %d tests correctly report the handCount has not changed\n", NUM_TESTS, handCount_test);
	printf("Out of %d tests, %d tests correctly incremented the number of actions by one\n", NUM_TESTS, numactions_test);
	printf("Out of %d tests, %d tests correctly discard the great_hall card\n", NUM_TESTS, discard_test);
	printf("Out of %d tests, %d tests correctly place the great_hall card in the playedCards pile\n", NUM_TESTS, played_test);
	
	
	return 0;
}


/* FOR REFERENCE
    case great_hall:
      //+1 Card
      drawCard(currentPlayer, state);
                        
      //+1 Actions
      state->numActions++;
                        
      //discard card from hand
      discardCard(handPos, currentPlayer, state, 0);
      return 0;
*/


